#include "mdict.h"
#include <iostream>
#include <sstream>
#include <cstdlib>
using std::cout;
using std::endl;
using std::cerr;
using std::stringstream;
using namespace mdict;

void MachineDict::query_by_word(const string &word) {
    if (this->m_last_queried == word) {
        return;
    } else {
        this->m_last_queried = word; // 更新上次查询
        this->result_vec.clear(); // 清空结果
    }
    string sql = "SELECT * FROM stardict WHERE sw='" + word + "';";
    char *error = nullptr;
    sqlite3_exec(this->conn, sql.c_str(), static_store_callback, this, &error);
    if (error) {
        cerr << error << endl;
    }
}

int MachineDict::get_collinsstar_by_word(const string &word) {
    query_by_word(word);
    return this->result_vec[0].collins_star;
}

vector<string> &MachineDict::get_examples_by_word(const string &word) {
    query_by_word(word);
    return this->result_vec[0].examples;
}

string &MachineDict::get_pronunciation_by_word(const string &word) {
    query_by_word(word);
    return this->result_vec[0].pronunciation;
}

vector<string> &MachineDict::get_translation_by_word(const string &word) {
    query_by_word(word);
    return this->result_vec[0].translation;
}

vector<string> &MachineDict::get_definition_by_word(const string &word) {
    query_by_word(word);
    return this->result_vec[0].definition;
}

vector<string> &MachineDict::get_changes_by_word(const string &word) {
    query_by_word(word);
    return this->result_vec[0].changes;
}

vector<wordentry_t> &MachineDict::get_result_by_range(unsigned int start, unsigned int end) {
    this->m_last_queried = ""; // 清空上次查询的单个缓存
    this->result_vec.clear();
    if (start <= 0 || end <= 0) {
        cerr << "索引有误: 索引必须是大于零的整数!" << endl;
    } else if (start > end) {
        cerr << "索引有误: 下界不应该大于上界!" << endl;
    } else {
        end = (end <= (start + MAX_RECORDS - 1) ? end : (start + MAX_RECORDS - 1)); // 通过MAX_RECORDS调整结束位置
        // 首先获取整张表的大小，检验索引是否正确
        string sql = "SELECT count(id) FROM stardict;";
        int row_count = 0;
        char *error = nullptr;
        sqlite3_exec(this->conn, sql.c_str(), get_count_callback, &row_count, &error);
        if (error) {
            cerr << error << endl;
            free(error);
        }
        if (start > row_count || end > row_count) {
            cerr << "索引越界: 最多只有" << row_count << "条记录!" << endl;
            return this->result_vec;
        }
        stringstream buffer;
        buffer << "SELECT * FROM stardict WHERE id >= " << start << " and id <= " << end << ";";
        sql = buffer.str();
        sqlite3_exec(this->conn, sql.c_str(), static_store_callback, this, &error);
        if (error) {
            cerr << error << endl;
            free(error);
        }
    }
    return this->result_vec;
}

vector<wordentry_t> &MachineDict::get_result_vector() {
    return this->result_vec;
}

wordentry_t &MachineDict::get_allinfo_by_word(const string &word) {
    query_by_word(word);
    return this->result_vec[0];
}

MachineDict::MachineDict() {
    this->conn = nullptr;
    auto rc = sqlite3_open("stardict.db", &this->conn);
    if (rc != SQLITE_OK) {
        cerr << "Can't open the database." << endl;
    }
    this->result_vec.emplace_back();
}

MachineDict::~MachineDict() {
    sqlite3_close(this->conn);
}

int MachineDict::store_callback(char **argv) {
    // 放置到result_vec中
    wordentry_t result;
    result.word = string(argv[2]);
    result.collins_star = argv[7] ? atoi(argv[7]) : NO_STAR;
    if (argv[12]) {
        auto changes_string = string(argv[12]);
        split_string(changes_string, result.changes, "/");
    }
    if (argv[4]) {
        auto definition = string(argv[4]);
        split_string(definition, result.definition, "\n");
    }
    if (argv[5]) {
        auto translation = string(argv[5]);
        split_string(translation, result.translation, "\n");
    }
    if (argv[13]) {
        auto examples = string(argv[13]);
        split_string(examples, result.examples, "\n");
    }
    if (argv[3]) {
        result.pronunciation = string(argv[3]);
    }
    this->result_vec.push_back(result);
    return 0;
}

int static_store_callback(void *data, int argc, char **argv, char **col_name) {
    auto dict = (MachineDict *)data;
    return dict->store_callback(argv);
}

void split_string(const string &s, vector<string> &v, const string &c) {
    string::size_type pos1, pos2;
    pos2 = s.find(c);
    pos1 = 0;
    while(string::npos != pos2)
    {
        v.push_back(s.substr(pos1, pos2-pos1));

        pos1 = pos2 + c.size();
        pos2 = s.find(c, pos1);
    }
    if(pos1 != s.length())
        v.push_back(s.substr(pos1));
}

int get_count_callback(void *result, int argc, char **argv, char **col_name) {
    *(int *)result = atoi(argv[0]);
    return 0;
}
